// This is JDefenceTower, a simple tower defence style game
//
// Copyright (C) 2010 Maximilian Junker
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, see <http://www.gnu.org/licenses/>.

package junker.defence.model;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Map {
	private static final Logger	logger		= Logger.getLogger(Map.class
													.getName());

	private List<MapObject>		mapObjects	= new LinkedList<MapObject>();
	private Grid				grid;
	private int					sizeX;
	private int					sizeY;
	private List<IMapEventListener> listeners = new LinkedList<IMapEventListener>();

	private MapLocation		sink;
	
	private Player player;

	public Map(int sizeX, int sizeY, MapLocation sink) {
		this.sizeX = sizeX;
		this.sizeY = sizeY;
		this.sink = sink;
		this.grid = new Grid(sizeX, sizeY, sink);
	}

	/**
	 * Adds the MapObject <em>o</em> to this map given by the grid location
	 * <em>loc</em>.
	 * 
	 * @param o
	 * @param loc
	 */
	public void addMapObject(MapObject o, MapLocation loc) {
		assert o.getMap() == null;
		assert o.getLocation() == null;

		if (grid.isBlocked(loc)) {
			logger.log(Level.WARNING,
					"Attempt to add MapObject at blocked location");
			return;
		}

		o.setLocation(loc);
		o.setMap(this);
		mapObjects.add(o);

		if (o.getMapObjectDescription().isBarrier()) {
			grid.blockLocation(loc);
		}
		
		notifyListenersCreate(o);
	}

	public Path findPathToSink(MapLocation location) {
		int lx = (int) location.getX();
		int ly = (int) location.getY();

		assert (lx == location.getX() || ly == location.getY());

		if (lx == location.getX() && ly == location.getY())
			return grid.findShortestPath(Arrays
					.asList(new MapLocation(lx, ly)));
		else if (lx == location.getX())
			return grid.findShortestPath(Arrays.asList(new MapLocation(
					lx, ly), new MapLocation(
					lx, ly+1)));
		else
			return grid.findShortestPath(Arrays.asList(new MapLocation(
					lx, ly), new MapLocation(
					lx+1, ly)));
	}

	public boolean isMapLocationBlocked(MapLocation MapLocation) {
		return grid.isBlocked(MapLocation);
	}


	public List<GameRequest> collectRequests(StepSummary s, TimeSpan span) {
		List<GameRequest> requests = new LinkedList<GameRequest>();
		for(MapObject o : mapObjects){
			requests.addAll(o.collectRequests(s, span));
		}
		return requests;
	}
	
	public void disableShortestPathCalculation(){
		grid.disableShortestPathCalculation();
	}
	
	public void enableShortestPathCalculation(){
		grid.enableShortestPathCalculation();
	}

	public void addMapEventListener(IMapEventListener listener) {
		listeners.add(listener);
	}
	
	private void notifyListenersCreate(MapObject o){
		for(IMapEventListener l : listeners){
			l.objectCreated(o);
		}
	}

	public int getSizeX() {
		return sizeX;
	}

	public void setSizeX(int sizeX) {
		this.sizeX = sizeX;
	}

	public int getSizeY() {
		return sizeY;
	}

	public void setSizeY(int sizeY) {
		this.sizeY = sizeY;
	}

	public Player getPlayer() {
		return player;
	}

	public void setPlayer(Player player) {
		this.player=player;
		
	}
	
	

}
